<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>5.6 项目整体流程代码实现</title><style>
/* cspell:disable-file */
/* webkit printing magic: print all background colors */
html {
	-webkit-print-color-adjust: exact;
}
* {
	box-sizing: border-box;
	-webkit-print-color-adjust: exact;
}

html,
body {
	margin: 0;
	padding: 0;
}
@media only screen {
	body {
		margin: 2em auto;
		max-width: 900px;
		color: rgb(55, 53, 47);
	}
}

body {
	line-height: 1.5;
	white-space: pre-wrap;
}

a,
a.visited {
	color: inherit;
	text-decoration: underline;
}

.pdf-relative-link-path {
	font-size: 80%;
	color: #444;
}

h1,
h2,
h3 {
	letter-spacing: -0.01em;
	line-height: 1.2;
	font-weight: 600;
	margin-bottom: 0;
}

.page-title {
	font-size: 2.5rem;
	font-weight: 700;
	margin-top: 0;
	margin-bottom: 0.75em;
}

h1 {
	font-size: 1.875rem;
	margin-top: 1.875rem;
}

h2 {
	font-size: 1.5rem;
	margin-top: 1.5rem;
}

h3 {
	font-size: 1.25rem;
	margin-top: 1.25rem;
}

.source {
	border: 1px solid #ddd;
	border-radius: 3px;
	padding: 1.5em;
	word-break: break-all;
}

.callout {
	border-radius: 3px;
	padding: 1rem;
}

figure {
	margin: 1.25em 0;
	page-break-inside: avoid;
}

figcaption {
	opacity: 0.5;
	font-size: 85%;
	margin-top: 0.5em;
}

mark {
	background-color: transparent;
}

.indented {
	padding-left: 1.5em;
}

hr {
	background: transparent;
	display: block;
	width: 100%;
	height: 1px;
	visibility: visible;
	border: none;
	border-bottom: 1px solid rgba(55, 53, 47, 0.09);
}

img {
	max-width: 100%;
}

@media only print {
	img {
		max-height: 100vh;
		object-fit: contain;
	}
}

@page {
	margin: 1in;
}

.collection-content {
	font-size: 0.875rem;
}

.column-list {
	display: flex;
	justify-content: space-between;
}

.column {
	padding: 0 1em;
}

.column:first-child {
	padding-left: 0;
}

.column:last-child {
	padding-right: 0;
}

.table_of_contents-item {
	display: block;
	font-size: 0.875rem;
	line-height: 1.3;
	padding: 0.125rem;
}

.table_of_contents-indent-1 {
	margin-left: 1.5rem;
}

.table_of_contents-indent-2 {
	margin-left: 3rem;
}

.table_of_contents-indent-3 {
	margin-left: 4.5rem;
}

.table_of_contents-link {
	text-decoration: none;
	opacity: 0.7;
	border-bottom: 1px solid rgba(55, 53, 47, 0.18);
}

table,
th,
td {
	border: 1px solid rgba(55, 53, 47, 0.09);
	border-collapse: collapse;
}

table {
	border-left: none;
	border-right: none;
}

th,
td {
	font-weight: normal;
	padding: 0.25em 0.5em;
	line-height: 1.5;
	min-height: 1.5em;
	text-align: left;
}

th {
	color: rgba(55, 53, 47, 0.6);
}

ol,
ul {
	margin: 0;
	margin-block-start: 0.6em;
	margin-block-end: 0.6em;
}

li > ol:first-child,
li > ul:first-child {
	margin-block-start: 0.6em;
}

ul > li {
	list-style: disc;
}

ul.to-do-list {
	padding-inline-start: 0;
}

ul.to-do-list > li {
	list-style: none;
}

.to-do-children-checked {
	text-decoration: line-through;
	opacity: 0.375;
}

ul.toggle > li {
	list-style: none;
}

ul {
	padding-inline-start: 1.7em;
}

ul > li {
	padding-left: 0.1em;
}

ol {
	padding-inline-start: 1.6em;
}

ol > li {
	padding-left: 0.2em;
}

.mono ol {
	padding-inline-start: 2em;
}

.mono ol > li {
	text-indent: -0.4em;
}

.toggle {
	padding-inline-start: 0em;
	list-style-type: none;
}

/* Indent toggle children */
.toggle > li > details {
	padding-left: 1.7em;
}

.toggle > li > details > summary {
	margin-left: -1.1em;
}

.selected-value {
	display: inline-block;
	padding: 0 0.5em;
	background: rgba(206, 205, 202, 0.5);
	border-radius: 3px;
	margin-right: 0.5em;
	margin-top: 0.3em;
	margin-bottom: 0.3em;
	white-space: nowrap;
}

.collection-title {
	display: inline-block;
	margin-right: 1em;
}

.page-description {
    margin-bottom: 2em;
}

.simple-table {
	margin-top: 1em;
	font-size: 0.875rem;
	empty-cells: show;
}
.simple-table td {
	height: 29px;
	min-width: 120px;
}

.simple-table th {
	height: 29px;
	min-width: 120px;
}

.simple-table-header-color {
	background: rgb(247, 246, 243);
	color: black;
}
.simple-table-header {
	font-weight: 500;
}

time {
	opacity: 0.5;
}

.icon {
	display: inline-block;
	max-width: 1.2em;
	max-height: 1.2em;
	text-decoration: none;
	vertical-align: text-bottom;
	margin-right: 0.5em;
}

img.icon {
	border-radius: 3px;
}

.user-icon {
	width: 1.5em;
	height: 1.5em;
	border-radius: 100%;
	margin-right: 0.5rem;
}

.user-icon-inner {
	font-size: 0.8em;
}

.text-icon {
	border: 1px solid #000;
	text-align: center;
}

.page-cover-image {
	display: block;
	object-fit: cover;
	width: 100%;
	max-height: 30vh;
}

.page-header-icon {
	font-size: 3rem;
	margin-bottom: 1rem;
}

.page-header-icon-with-cover {
	margin-top: -0.72em;
	margin-left: 0.07em;
}

.page-header-icon img {
	border-radius: 3px;
}

.link-to-page {
	margin: 1em 0;
	padding: 0;
	border: none;
	font-weight: 500;
}

p > .user {
	opacity: 0.5;
}

td > .user,
td > time {
	white-space: nowrap;
}

input[type="checkbox"] {
	transform: scale(1.5);
	margin-right: 0.6em;
	vertical-align: middle;
}

p {
	margin-top: 0.5em;
	margin-bottom: 0.5em;
}

.image {
	border: none;
	margin: 1.5em 0;
	padding: 0;
	border-radius: 0;
	text-align: center;
}

.code,
code {
	background: rgba(135, 131, 120, 0.15);
	border-radius: 3px;
	padding: 0.2em 0.4em;
	border-radius: 3px;
	font-size: 85%;
	tab-size: 2;
}

code {
	color: #eb5757;
}

.code {
	padding: 1.5em 1em;
}

.code-wrap {
	white-space: pre-wrap;
	word-break: break-all;
}

.code > code {
	background: none;
	padding: 0;
	font-size: 100%;
	color: inherit;
}

blockquote {
	font-size: 1.25em;
	margin: 1em 0;
	padding-left: 1em;
	border-left: 3px solid rgb(55, 53, 47);
}

.bookmark {
	text-decoration: none;
	max-height: 8em;
	padding: 0;
	display: flex;
	width: 100%;
	align-items: stretch;
}

.bookmark-title {
	font-size: 0.85em;
	overflow: hidden;
	text-overflow: ellipsis;
	height: 1.75em;
	white-space: nowrap;
}

.bookmark-text {
	display: flex;
	flex-direction: column;
}

.bookmark-info {
	flex: 4 1 180px;
	padding: 12px 14px 14px;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
}

.bookmark-image {
	width: 33%;
	flex: 1 1 180px;
	display: block;
	position: relative;
	object-fit: cover;
	border-radius: 1px;
}

.bookmark-description {
	color: rgba(55, 53, 47, 0.6);
	font-size: 0.75em;
	overflow: hidden;
	max-height: 4.5em;
	word-break: break-word;
}

.bookmark-href {
	font-size: 0.75em;
	margin-top: 0.25em;
}

.sans { font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; }
.code { font-family: "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace; }
.serif { font-family: Lyon-Text, Georgia, ui-serif, serif; }
.mono { font-family: iawriter-mono, Nitti, Menlo, Courier, monospace; }
.pdf .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK JP'; }
.pdf:lang(zh-CN) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK SC'; }
.pdf:lang(zh-TW) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK TC'; }
.pdf:lang(ko-KR) .sans { font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol", 'Twemoji', 'Noto Color Emoji', 'Noto Sans CJK KR'; }
.pdf .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK JP'; }
.pdf:lang(zh-CN) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK SC'; }
.pdf:lang(zh-TW) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK TC'; }
.pdf:lang(ko-KR) .code { font-family: Source Code Pro, "SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK KR'; }
.pdf .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK JP'; }
.pdf:lang(zh-CN) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK SC'; }
.pdf:lang(zh-TW) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK TC'; }
.pdf:lang(ko-KR) .serif { font-family: PT Serif, Lyon-Text, Georgia, ui-serif, serif, 'Twemoji', 'Noto Color Emoji', 'Noto Serif CJK KR'; }
.pdf .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK JP'; }
.pdf:lang(zh-CN) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK SC'; }
.pdf:lang(zh-TW) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK TC'; }
.pdf:lang(ko-KR) .mono { font-family: PT Mono, iawriter-mono, Nitti, Menlo, Courier, monospace, 'Twemoji', 'Noto Color Emoji', 'Noto Sans Mono CJK KR'; }
.highlight-default {
	color: rgba(55, 53, 47, 1);
}
.highlight-gray {
	color: rgba(120, 119, 116, 1);
	fill: rgba(120, 119, 116, 1);
}
.highlight-brown {
	color: rgba(159, 107, 83, 1);
	fill: rgba(159, 107, 83, 1);
}
.highlight-orange {
	color: rgba(217, 115, 13, 1);
	fill: rgba(217, 115, 13, 1);
}
.highlight-yellow {
	color: rgba(203, 145, 47, 1);
	fill: rgba(203, 145, 47, 1);
}
.highlight-teal {
	color: rgba(68, 131, 97, 1);
	fill: rgba(68, 131, 97, 1);
}
.highlight-blue {
	color: rgba(51, 126, 169, 1);
	fill: rgba(51, 126, 169, 1);
}
.highlight-purple {
	color: rgba(144, 101, 176, 1);
	fill: rgba(144, 101, 176, 1);
}
.highlight-pink {
	color: rgba(193, 76, 138, 1);
	fill: rgba(193, 76, 138, 1);
}
.highlight-red {
	color: rgba(212, 76, 71, 1);
	fill: rgba(212, 76, 71, 1);
}
.highlight-gray_background {
	background: rgba(241, 241, 239, 1);
}
.highlight-brown_background {
	background: rgba(244, 238, 238, 1);
}
.highlight-orange_background {
	background: rgba(251, 236, 221, 1);
}
.highlight-yellow_background {
	background: rgba(251, 243, 219, 1);
}
.highlight-teal_background {
	background: rgba(237, 243, 236, 1);
}
.highlight-blue_background {
	background: rgba(231, 243, 248, 1);
}
.highlight-purple_background {
	background: rgba(244, 240, 247, 0.8);
}
.highlight-pink_background {
	background: rgba(249, 238, 243, 0.8);
}
.highlight-red_background {
	background: rgba(253, 235, 236, 1);
}
.block-color-default {
	color: inherit;
	fill: inherit;
}
.block-color-gray {
	color: rgba(120, 119, 116, 1);
	fill: rgba(120, 119, 116, 1);
}
.block-color-brown {
	color: rgba(159, 107, 83, 1);
	fill: rgba(159, 107, 83, 1);
}
.block-color-orange {
	color: rgba(217, 115, 13, 1);
	fill: rgba(217, 115, 13, 1);
}
.block-color-yellow {
	color: rgba(203, 145, 47, 1);
	fill: rgba(203, 145, 47, 1);
}
.block-color-teal {
	color: rgba(68, 131, 97, 1);
	fill: rgba(68, 131, 97, 1);
}
.block-color-blue {
	color: rgba(51, 126, 169, 1);
	fill: rgba(51, 126, 169, 1);
}
.block-color-purple {
	color: rgba(144, 101, 176, 1);
	fill: rgba(144, 101, 176, 1);
}
.block-color-pink {
	color: rgba(193, 76, 138, 1);
	fill: rgba(193, 76, 138, 1);
}
.block-color-red {
	color: rgba(212, 76, 71, 1);
	fill: rgba(212, 76, 71, 1);
}
.block-color-gray_background {
	background: rgba(241, 241, 239, 1);
}
.block-color-brown_background {
	background: rgba(244, 238, 238, 1);
}
.block-color-orange_background {
	background: rgba(251, 236, 221, 1);
}
.block-color-yellow_background {
	background: rgba(251, 243, 219, 1);
}
.block-color-teal_background {
	background: rgba(237, 243, 236, 1);
}
.block-color-blue_background {
	background: rgba(231, 243, 248, 1);
}
.block-color-purple_background {
	background: rgba(244, 240, 247, 0.8);
}
.block-color-pink_background {
	background: rgba(249, 238, 243, 0.8);
}
.block-color-red_background {
	background: rgba(253, 235, 236, 1);
}
.select-value-color-interactiveBlue { background-color: rgba(35, 131, 226, .07); }
.select-value-color-pink { background-color: rgba(245, 224, 233, 1); }
.select-value-color-purple { background-color: rgba(232, 222, 238, 1); }
.select-value-color-green { background-color: rgba(219, 237, 219, 1); }
.select-value-color-gray { background-color: rgba(227, 226, 224, 1); }
.select-value-color-translucentGray { background-color: rgba(255, 255, 255, 0.0375); }
.select-value-color-orange { background-color: rgba(250, 222, 201, 1); }
.select-value-color-brown { background-color: rgba(238, 224, 218, 1); }
.select-value-color-red { background-color: rgba(255, 226, 221, 1); }
.select-value-color-yellow { background-color: rgba(253, 236, 200, 1); }
.select-value-color-blue { background-color: rgba(211, 229, 239, 1); }
.select-value-color-pageGlass { background-color: undefined; }
.select-value-color-washGlass { background-color: undefined; }

.checkbox {
	display: inline-flex;
	vertical-align: text-bottom;
	width: 16;
	height: 16;
	background-size: 16px;
	margin-left: 2px;
	margin-right: 5px;
}

.checkbox-on {
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Crect%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%2358A9D7%22%2F%3E%0A%3Cpath%20d%3D%22M6.71429%2012.2852L14%204.9995L12.7143%203.71436L6.71429%209.71378L3.28571%206.2831L2%207.57092L6.71429%2012.2852Z%22%20fill%3D%22white%22%2F%3E%0A%3C%2Fsvg%3E");
}

.checkbox-off {
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Crect%20x%3D%220.75%22%20y%3D%220.75%22%20width%3D%2214.5%22%20height%3D%2214.5%22%20fill%3D%22white%22%20stroke%3D%22%2336352F%22%20stroke-width%3D%221.5%22%2F%3E%0A%3C%2Fsvg%3E");
}
	
</style></head><body><article id="9acaf4be-0fab-46e7-863c-026eee94f536" class="page sans"><header><h1 class="page-title">5.6 项目整体流程代码实现</h1><p class="page-description"></p></header><div class="page-body"><p id="9ef1a3fd-7a82-4846-afbc-56057d529d0b" class="">前面搭完了一些简单的小组件，主要是完成了线程池的内容</p><p id="45b0ddcb-a95b-47c9-b2f7-3d9b0f102053" class="">接下来要编写socket连接相关的代码</p><p id="3a66bd66-8d4b-4713-ab25-5dd10fb5424b" class="">要实现的功能：</p><p id="9cdcfbb8-69f0-424a-9ba5-8b9cfa3f15bc" class="">1.判断初始参数：</p><p id="0a5f8e9a-613f-49c9-8485-33fbd493cef8" class="">argc是参数的个数，我们希望传递至少一个端口号进去
basename是一个基础的程序的名称</p><pre id="45c64a66-d312-4e2c-bca3-42d1e9b8dccc" class="code"><code>int main(int argc, char* argv[]){
    if(argc &lt;= 1){      // 形参个数，第一个为执行命令的名称
        EMlog(LOGLEVEL_ERROR,&quot;run as: %s port_number\n&quot;, basename(argv[0]));      // argv[0] 可能是带路径的，用basename转换
        exit(-1);
    }
}</code></pre><p id="121ec145-86dc-4440-8cc0-3a0b7a97295f" class="">2.获取端口号：</p><p id="2b07d387-e73d-4b40-af07-d0256a1786ba" class="">atoi代表ascii(字符串)到int形</p><pre id="aa6229e0-7bc8-40df-aea3-7959149fe85b" class="code"><code>// 获取端口号
int port = atoi(argv[1]);   // 字符串转整数</code></pre><p id="a70f7243-954f-48ff-a44f-39439006228c" class="">3.添加信号捕捉：屏蔽sigpipe信号，防止因为一端端口关闭导致异常</p><p id="efaf71f7-16da-4058-9e8c-e233c1bc9d8e" class="">用sigaction来接受信号</p><pre id="5d5a1ca7-9a0c-4f02-9810-525b21a8819a" class="code"><code>// 信号处理，添加信号捕捉
void addsig(int sig, void(handler)(int)){       
    struct sigaction sigact;                    // sig 指定信号， void handler(int) 为处理函数
    memset(&amp;sigact, &#x27;\0&#x27;, sizeof(sigact));      // bezero 清空
    sigact.sa_flags = 0;                        // 调用sa_handler
    // sigact.sa_flags |= SA_RESTART;                  // 指定收到某个信号时是否可以自动恢复函数执行，不需要中断后自己判断EINTR错误信号
    sigact.sa_handler = handler;                // 指定回调函数
    sigfillset(&amp;sigact.sa_mask);                // 将临时阻塞信号集中的所有的标志位置为1，即都阻塞
    sigaction(sig, &amp;sigact, NULL);              // 设置信号捕捉sig信号值
}
// 对SIGPIE信号进行处理(捕捉忽略，默认退出)
addsig(SIGPIPE, SIG_IGN);           // https://blog.csdn.net/chengcheng1024/article/details/108104507</code></pre><p id="2e416bb7-96d2-48a5-b6c9-16d8f7a0043d" class="">4.创建线程池：</p><p id="74d43f60-f65a-45aa-baba-3fe79627615a" class="">线程池是用模板类写的，里面可以填我们想要的类。但是一次连接需要的参数就很多，所以我们直接写一个http_conn类出来，代表一个连接请求</p><pre id="8961e745-c830-404e-a74c-5ab90c1e2936" class="code"><code>// 创建线程池，初始化线程池
threadpool&lt;http_conn&gt; * pool = NULL;    // 模板类 指定任务类类型为 http_conn
try{
    pool = new threadpool&lt;http_conn&gt;;
}catch(...){
    exit(-1);
}</code></pre><p id="c6646523-d7e4-426d-b2a5-4bc6ad920743" class="">5.完成http_conn类：</p><p id="edf6595c-0198-4d18-81b0-f739e8633bcd" class="">构造函数，析构函数，process()处理客户端请求函数</p><p id="2a9cb1e9-3fbc-4be2-8bef-f99a7f230ca1" class="">（proactor模式，数据在交给工作线程就已经获取了，所以我们的目标就是解析http请求）</p><p id="208d1cea-881a-4b3a-9d68-36d25e54e8ff" class="">[9以后写的]静态类：epool的文件描述符（确实只有一个，但是移交给http_conn类感觉怪怪的），统计用户的数量</p><p id="f55f1159-8ce7-465c-b342-44fe486d3519" class="">[9以后写的]私有成员：连接的socket文件描述符，客户端的地址信息</p><p id="54639da6-5e57-4f43-95fe-150bf811359d" class="">[9以后写的]共有成员：初始化函数（初始化文件描述和地址，端口复用，添加到epool对象，总用户数++）</p><pre id="e6187896-9a7f-4e93-85f7-13154f63b376" class="code"><code>// http 连接的用户数据类
class http_conn
{
public:                         // 共享对象，没有线程竞争资源，所以不需要互斥
    static int m_epoll_fd;      // 所有的socket上的事件都被注册到同一个epoll对象中
    static int m_user_cnt;      // 统计用户的数量
public:
    http_conn();
    ~http_conn();
    void process();     // 处理客户端的请求、对客户端的响应
    void init(int sock_fd, const sockaddr_in&amp; addr);    // 初始化新的连接
    void conn_close();  // 关闭连接
    bool read();        // 非阻塞的读
    bool write();       // 非阻塞的写

private:
    int m_sock_fd;                  // 该http连接的socket
    sockaddr_in m_addr;             // 通信的socket地址
};</code></pre><p id="11cebb06-ae28-46c4-baf8-1e2f815f7bbd" class="">6.创建一个数组来保存接收到的所有的客户信息events</p><pre id="d2139529-3ef2-4b2b-92eb-e56fd82bf756" class="code"><code>// 创建一个保存所有客户端信息的数组
http_conn* users = new http_conn[MAX_FD];
http_conn::m_epoll_fd = epoll_fd;       // 静态成员，类共享</code></pre><p id="75e4ee91-4eac-4bdd-9f87-a95190d7d0dd" class="">7.tcp网络编程代码准备：</p><p id="c7302d5b-4530-4368-ae95-d4eb92f6e698" class="">即创建socket记录文件描述符，设置端口复用setsocketopt，绑定bind文件描述符和绑定地址，监听listen文件描述符，创建epool对象和事件数组</p><pre id="a85d7246-f970-47f7-b527-46434c2d4a3d" class="code"><code>		int listen_fd = socket(AF_INET, SOCK_STREAM, 0);    // 监听套接字
    assert( listen_fd &gt;= 0 );                            // ...判断是否创建成功
    
    // 设置端口复用
    int reuse = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, &amp;reuse, sizeof(reuse));

    // 绑定
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    int ret = bind(listen_fd, (struct sockaddr*)&amp;addr, sizeof(addr));
    assert( ret != -1 );    // ...判断是否成功

    // 监听
    ret = listen(listen_fd, 8);
    assert( ret != -1 );    // ...判断是否成功

    // 创建epoll对象，事件数组（IO多路复用，同时检测多个事件）
    epoll_event events[MAX_EVENT_SIZE]; // 结构体数组，接收检测后的数据
    int epoll_fd = epoll_create(5);     // 参数 5 无意义， &gt; 0 即可
    
    assert( epoll_fd != -1 );</code></pre><p id="e06c9774-6ace-4499-b6ed-6c395fa7ee9a" class="">8.添加/删除/修改epool中的文件描述符函数：</p><p id="d42f40c1-7afc-4474-aa2b-3865ad6f3e34" class="">要知道epool的文件描述符和要添加/删除/修改的文件描述符</p><p id="f8cd6216-9cf2-4594-9fb8-756cf2b38eeb" class="">添加的时候要设置文件描述符的读为非阻塞</p><p id="1e0a29ea-aa1e-4601-b155-8d9b18eb2ad0" class="">注意epolloneshot事件（与ET触发无关，是两个维度的事情），只针对一个文件描述符，操作系统最多触发一次，防止被重复唤醒其他线程处理。除非重新注册该事件（自己写的修改函数）</p><pre id="6524538f-6a57-4439-a87e-e374c5a97996" class="code"><code>// 添加需要监听的文件描述符到epoll中
void addfd(int epoll_fd, int fd, bool one_shot, bool et){
    epoll_event event;
    event.data.fd = fd;
    if(et){
        event.events = EPOLLIN | EPOLLRDHUP | EPOLLET;  // 对所有fd设置边沿触发，但是listen_fd不需要，可以另行判断处理
    }else{
        event.events = EPOLLIN | EPOLLRDHUP;    // 默认水平触发    对端连接断开触发的epoll 事件包含 EPOLLIN | EPOLLRDHUP挂起，不用根据返回值判断，直接通过事件判断异常断开
    }
    if(one_shot){
        event.events |= EPOLLONESHOT;       // 注册为 EPOLLONESHOT事件，防止同一个通信被不同的线程处理
    }
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &amp;event);

    // 设置文件描述符为非阻塞（epoll ET模式）
    set_nonblocking(fd);
}


// 从epoll中删除文件描述符
void rmfd(int epoll_fd, int fd){
    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, 0);
    close(fd);
}


// 在epoll中修改文件描述符，重置socket上EPOLLONESHOT事件，确保下次可读时，EPOLLIN 事件被触发
void modfd(int epoll_fd, int fd, int ev){
    epoll_event event;
    event.data.fd = fd;
    event.events = ev | EPOLLONESHOT | EPOLLRDHUP;
    epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &amp;event);
}</code></pre><p id="d06e5786-b2fa-441e-a32d-943a0c1d3666" class="">9.调用8写的添加函数，把初始socket丢进去，因为主线程就是监听线程，也要受epool管理</p><pre id="e7e30c1a-fbe8-45ef-93ad-a371c7f0d38a" class="code"><code>// 将监听的文件描述符添加到epoll对象中
addfd(epoll_fd, listen_fd, false, false);  // 监听文件描述符不需要 ONESHOT &amp; ET</code></pre><p id="603d45c7-81cc-45e2-9d53-ec2029aa9d9f" class="">10.while死循环，检测哪些事件发生：</p><p id="08a60909-c06b-4e3c-8e85-e7c52d733d27" class="">调用epool_wait，等待事件发生</p><p id="49a9cf06-be93-4e8b-9cf8-16ec51cab90d" class="">循环遍历事件数组events</p><p id="21de938e-29cf-4346-996f-4c75555bc3b4" class="">11.如果是有新socket接入，那就调用accept获取新socket的地址和连接的文件描述符。如果连接大于服务器连接数量，那就告诉客户端服务器正忙，然后关闭连接。如果连接数够用，那就简单的用文件描述符作为索引（因为是唯一且递增的），存到user数组里面（user数组的声明在events后线程池前（？），存下所有的http_conn信息）</p><p id="85165f8a-3bfe-46e9-a977-1f12094f998e" class="">12.如果有异常发生，那就要关闭连接：</p><p id="2a19942e-7158-4420-af55-4adda6991a40" class="">在http_conn里面加函数close，总用户数减少</p><p id="9c43b939-e911-405c-834a-4f008ef6c517" class="">13.如果有读事件发生：</p><p id="11c293a3-e684-4d34-b2d3-b199c63c3745" class="">我们要一次性把所有的数据读出来，在http_conn写个read()函数把所有数据都读完，然后移交给工作线程来处理业务逻辑</p><p id="366b80e3-f9a4-42a4-b7ae-0e3e70ed2415" class="">读失败了就断开连接</p><p id="da9d4577-0cff-4630-971c-2098a132cc0d" class="">14.如果有写事件发生：</p><p id="fa38da49-62b4-4f43-ab5d-4371fc176408" class="">我们要一次性把所有的数据写进去，在http_conn写个write()函数把所有数据都写完，然后关闭连接</p><pre id="938c550c-eda2-420e-9b89-fd28b70743e5" class="code"><code>	while(!stop_server){
        // 检测事件
        int num = epoll_wait(epoll_fd, events, MAX_EVENT_SIZE, -1);     // 阻塞，返回事件数量
        if(num &lt; 0 &amp;&amp; errno != EINTR){
            break;
        }

        // 循环遍历事件数组
        for(int i = 0; i &lt; num; ++i){

            int sock_fd = events[i].data.fd;
            if(sock_fd == listen_fd){   // 监听文件描述符的事件响应
                // 有客户端连接进来
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int conn_fd = accept(listen_fd,(struct sockaddr*)&amp;client_addr, &amp;client_addr_len);
                // ...判断是否连接成功
                if(http_conn::m_user_cnt &gt;= MAX_FD){
                    // 目前连接数满了
                    // ...给客户端写一个信息：服务器内部正忙
                    close(conn_fd);
                    continue;
                }
                // 将新客户端数据初始化，放到数组中
                users[conn_fd].init(conn_fd, client_addr);  // conn_fd 作为索引
                // 当listen_fd也注册了ONESHOT事件时(addfd)，
                // 接受了新的连接后需要重置socket上EPOLLONESHOT事件，确保下次可读时，EPOLLIN 事件被触发
                // modfd(epoll_fd, listen_fd, EPOLLIN); 
            }  
            else if(events[i].events &amp; (EPOLLRDHUP | EPOLLHUP | EPOLLERR)){
                // 对方异常断开 或 错误 等事件
                users[sock_fd].conn_close(); 
            }
            else if(events[i].events &amp; EPOLLIN){
                if (users[sock_fd].read()){         // 主进程一次性读取缓冲区的所有数据
                    pool-&gt;append(users + sock_fd);  // 加入到线程池队列中，数组指针 + 偏移 &amp;users[sock_fd]
                }else{
                    users[sock_fd].conn_close();
                }

            }
            else if(events[i].events &amp; EPOLLOUT){
                EMlog(LOGLEVEL_DEBUG, &quot;-------EPOLLOUT--------\n\n&quot;);
                if (!users[sock_fd].write()){       // 主进程一次性写完所有数据
                    users[sock_fd].conn_close();    // 写入失败
                }
            }
        }
    }</code></pre><p id="f9557cb4-a566-41cb-bb75-b2565194441a" class="">15.程序结束了要释放线程池和user数组，要释放epoll文件描述符和初始socket文件描述符</p><pre id="65bcce34-5eaa-4869-84c1-43c9bb8167a0" class="code"><code>		close(epoll_fd);
    close(listen_fd);
    delete[] users;
    delete pool;</code></pre><figure id="6a84ac47-1401-4bb4-a255-643293e47cc8"><div class="source"><a href="5%206%20%E9%A1%B9%E7%9B%AE%E6%95%B4%E4%BD%93%E6%B5%81%E7%A8%8B%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%209acaf4be0fab46e7863c026eee94f536/Untitled.txt">Untitled</a></div></figure><p id="7b6186f2-0057-4825-b641-711894d98876" class="">可能是notion的问题，自己下载后缀改成rar解压即可</p><p id="17df38b1-640e-466b-9b3c-b8aecb4b2584" class="">
</p></div></article></body></html>